package com.ad2campaign.engine.core.service;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javapns.Push;
import javapns.devices.Device;
import javapns.devices.implementations.basic.BasicDevice;
import javapns.notification.PushNotificationPayload;
import javapns.notification.PushedNotification;

import org.apache.log4j.Logger;
import org.json.JSONException;

import com.ad2campaign.engine.db.model.NotificationMessage;
import com.ad2campaign.engine.utils.KeystoreHolder;

public class IOSPushNotificationServiceImpl implements PushNotificationService{
	private static final Logger LOGGER = Logger.getLogger(IOSPushNotificationServiceImpl.class);

	private String message;
	private boolean isProduction;
	private String key_val;
	private int threads = 10;//default 10 threads

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public boolean isProduction() {
		return isProduction;
	}

	public String getKey_val() {
		return key_val;
	}

	public void setKey_val(String key_val) {
		this.key_val = key_val;
	}

	public void setProduction(boolean isProduction) {
		this.isProduction = isProduction;
	}

	public int getThreads() {
		return threads;
	}

	public void setThreads(int threads) {
		this.threads = threads;
	}

	public List<? extends NotificationMessage> sendPushNotification(List<? extends NotificationMessage> messages,KeystoreHolder keystoreHolder){

		if(messages.size()==0){
			LOGGER.info(" IOS ----- Empty list, not pushing to anyone -----");
			return messages;
		}
		
		/*
 		for (NotificationMessage message :  messages)
		{
 			message.setDelivered(1);
  			LOGGER.info("processing...");
 			message.setResponse("SUCCESS");
		}
		 */
		String notificationPushId = "";
		Iterator<? extends NotificationMessage> itr = messages.iterator();
		List<Device> devices = new ArrayList<Device>();
		while(itr.hasNext()){
			NotificationMessage message = itr.next();
			Device d = new BasicDevice();
			d.setToken(message.getTokenId());
			devices.add(d);
			notificationPushId = message.getnId()+"";
		}

		String exeptionText = "";
		PushNotificationPayload payload = PushNotificationPayload.complex();
		try {
			payload.addAlert(this.getMessage());
			payload.addSound("default");
			payload.addCustomDictionary("nId",notificationPushId);

			if(this.getKey_val() != null){
				String[] keyValArr = this.getKey_val().split("###");
				for(int i=0;i<keyValArr.length;i++){
					if(keyValArr[i].contains("=")){
						String[] kv = keyValArr[i].split("=");
						try{
							payload.addCustomDictionary(URLDecoder.decode(kv[0],"UTF-8"),URLDecoder.decode(kv[1],"UTF-8"));
						}catch (UnsupportedEncodingException e){
							LOGGER.info(notificationPushId+" @UnsupportedEncodingException:",e);
						}
					}
				}
			}
		} catch (JSONException e) {
			LOGGER.info(notificationPushId+" @JSONException:",e);
			exeptionText =  e.getMessage();
		}
		List<PushedNotification> notificationResult = null;
		ByteArrayInputStream keystore = new ByteArrayInputStream(keystoreHolder.getData());

		try {
			LOGGER.info(notificationPushId+" @Processing IOS notifications for batch of ["+devices.size()+"] devices.");
			LOGGER.info(notificationPushId+" @ >----->"+
					//", keystore cert = "+ keystoreHolder.getData().toString() +
					", keystore pwd = "+keystoreHolder.getPwd()+
					", message = "+this.getMessage()+
					", key_val = "+this.getKey_val()
					);

			notificationResult = Push.payload(payload, keystore, keystoreHolder.getPwd(), this.isProduction, this.threads, devices);
		} catch (Exception e) {
			LOGGER.info(notificationPushId+" @Exception:",e);
			exeptionText =  e.getMessage();
		}

		Iterator<PushedNotification> resIterator = notificationResult.iterator();
		while(resIterator.hasNext()){
			PushedNotification pn = resIterator.next();
			String resTokenID = pn.getDevice().getToken();
			String responseText = "";
			if(pn.isSuccessful()){
				responseText = "SUCCESS";
			}else{
				try{
					if(pn.getException()!=null){
						responseText = pn.getException().toString();
					}else{
						responseText = pn.getResponse().getStatus() +" : "+pn.getResponse().getMessage();
					}

				}catch(Exception e){
					LOGGER.info(notificationPushId+" @Exception:",e);
					exeptionText =  e.getMessage();
				}
			}
			if(responseText == null || responseText.equals(""))
				responseText = exeptionText;

			Iterator<? extends NotificationMessage> tempItr = messages.iterator();
			while(tempItr.hasNext()){
				NotificationMessage message = tempItr.next();
				if(resTokenID==message.getTokenId()){

					if(responseText.equalsIgnoreCase("SUCCESS")){
						message.setDelivered(1);
					}else{
						message.setDelivered(0);
					}
					message.setStatus(1);
					message.setResponse(responseText);
					break;
				}
			}
		}
		try 
		{
			LOGGER.debug(notificationPushId+" @sendPushNotification : Closing keystore inputsteam");
			if (keystore!=null)
			{
				keystore.close();
			}
		} catch (Exception e)
		{
			LOGGER.error(notificationPushId+" @sendPushNotification : Unable to close keystore inputsteam cause "+e.getMessage());
			LOGGER.debug(e.getMessage(), e);
		}

		return messages;
	}

}
